#pragma once

#include <qlib/all.h>
#include "../ecs/ecs.hpp"

#include "../ui_message/message.h"

namespace qbe::layer {

//填充的样式参数
struct FillParam {
  int type;     // 填充类型
  float width;  // 线宽/点半径
  float space;  // 间隔
  // float line_width;
  // float dot;
  // float angle;
  // float only_side;
  // float use_point_grid;
  // float scale;
};

//边框的参数
struct BorderParam {
  float dash{0.0};
  float gap{0.0};
};

struct RenderParam {
  vsg::vec4 fill_color;
  FillParam fill_param;
  vsg::vec4 border_color;
  BorderParam border_param;
};

static std::map<std::string, FillParam> FILL_TYPES_TABLE = {
    {"F0", {0, 0, 0}},  // 全填充
    {"F1", {1, 0, 0}},  // 关闭填充

    {"F2", {2, 1, 5}},   // 点阵1
    {"F3", {2, 1, 10}},  // 点阵2
    {"F4", {2, 2, 5}},   // 点阵3
    {"F5", {2, 2, 10}},  // 点阵4

    {"F6", {3, 1, 5}},   // 右斜线1
    {"F7", {3, 1, 10}},  // 右斜线2
    {"F8", {3, 2, 5}},   // 右斜线3
    {"F9", {3, 2, 10}},  // 右斜线4

    {"F10", {4, 1, 5}},   // 左斜线1
    {"F11", {4, 1, 10}},  // 左斜线2
    {"F12", {4, 2, 5}},   // 左斜线3
    {"F13", {4, 2, 10}},  // 左斜线4

    {"F14", {5, 1, 5}},   // 斜线网格1
    {"F15", {5, 1, 10}},  // 斜线网格2
    {"F16", {5, 2, 5}},   // 斜线网格3
    {"F17", {5, 2, 10}},  // 斜线网格4

    {"F99", {-1, 0, 0}},  //

    // {"F0", {-1, 0, 0, 0, 0, 0, 0, 1}},      // 填充
    // {"F1", {1, 5, 0, 0, 45, 0, 0, 1}},      // 斜线1
    // {"F2", {2, 5, 0, 0, 45, 0, 0, 1}},      // 斜线2
    // {"F3", {1, 5, 0, 0, 135, 0, 0, 1}},     // 斜线3
    // {"F4", {1, 10, 0, 0, 45, 1, 0, 1}},     // 斜网格
    // {"F5", {1, 10, 5, 10, 45, 0, 0, 1}},    // 间隙线
    // {"F6", {1, 15, 10, 5, 45, 0, 0, 1}},    // 循环方格点
    // {"F7", {1, 5, 0, 0, 45, 1, 1, 1}},      // 点阵密集
    // {"F8", {3, 5, 0, 0, 45, 1, 1, 1}},      // 点阵
    // {"F9", {1, 10, 5, 5, 45, 1, 0, 1}},     // 循环十字
    // {"F10", {1, 20, 10, 10, 0, 1, 0, 2}},   // 循环十字2
    // {"F11", {3, 20, 5, 5, 45, 1, 0, 2}},    // 特殊纹理1
    // {"F12", {2, 10, 20, 5, 45, 1, 0, 2}},   // 特殊纹理2
    // {"F13", {1, 5, 10, 5, 45, 1, 0, 1}},    // 特殊纹理3
    // {"F14", {2, 10, 10, 10, 45, 1, 0, 1}},  // 特殊纹理4
    // {"F99", {0, 0, 0, 0, 0, 0, 0, 0}},      // 特殊纹理4
};

static std::map<std::string, BorderParam> BORDER_TYPES_TABLE = {
    {"B1", {0, 0}},     //
    {"B2", {100, 70}},  //
    {"B3", {50, 50}},   //
    {"B4", {20, 20}},   //
    {"B5", {10, 10}},   //
    {"B99", {1.5, 3}},  //
};

static vsg::vec4 to_rgb(const std::string& fill_color) {
  QColor qc(fill_color.c_str());
  int r, g, b;
  qc.getRgb(&r, &g, &b);
  return vsg::vec4(r / 255.0, g / 255.0, b / 255.0, 1.0);
}

struct Info {
  UiMessage::LayerItemInfo layer_param;  // 渲染参数
  RenderParam render_param;              // 渲染参数

  std::string layer_name;    // 图层名
  uint32_t layer_number;     // 图层编号
  bool layer_lock{false};    // 是否锁定
  bool layer_hide{false};    // 是否隐藏
  bool layer_export{true};   // 是否导出
  vsg::vec4 fill_color;      // 填充颜色
  FillParam fill_param;      // 填充样式
  vsg::vec4 border_color;    // 边框颜色
  BorderParam border_param;  // 边框样式

  void load_layer(UiMessage::LayerItemInfo& _layer_param) {
    layer_param = _layer_param;
    update_render();
  }

  void load(UiMessage::LayerItemInfo& item) {
    layer_name = item.layer_name;
    layer_number = item.layer_number;
    layer_lock = item.layer_lock;
    layer_hide = item.layer_hide;
    layer_export = item.layer_export;

    fill_color = to_rgb(item.fill_color);
    fill_param = FILL_TYPES_TABLE[item.fill_shape];
    border_color = to_rgb(item.border_color);
    border_param = BORDER_TYPES_TABLE[item.border_shape];
  }

  void load(uint32_t num, std::vector<std::string>& item) {
    layer_number = num;
    fill_color = to_rgb(item[0]);
    border_color = to_rgb(item[1]);
    fill_param = FILL_TYPES_TABLE[item[2]];
    border_param = BORDER_TYPES_TABLE[item[3]];
    layer_name = item[4];
    layer_lock = item[5] == "lock" ? true : false;
    layer_hide = item[6] == "hide" ? true : false;
  }

  void update_render() {}

  void random() {
    float r = (qrand() % 255) / 255.0;
    float g = (qrand() % 255) / 255.0;
    float b = (qrand() % 255) / 255.0;

    fill_color = vsg::vec4{r, g, b, 0.0};
    fill_param = FILL_TYPES_TABLE["F1"];
    border_color = vsg::vec4{r, g, b, 0.0};
    border_param = BORDER_TYPES_TABLE["B1"];
  }

  void setColor(float r, float g, float b) {
    fill_color = vsg::vec4{r, g, b, 0.0};
    fill_param = FILL_TYPES_TABLE["F1"];
    border_color = vsg::vec4{r, g, b, 0.0};
    border_param = BORDER_TYPES_TABLE["B1"];
  }
};

struct Model {
  std::unordered_map<qlib::Tag, Info, qlib::Tag::Hash> layers;

  Model();
  ~Model();

  void add(qlib::Tag& tag);
  void add(UiMessage::LayerItemInfo& item);
  void edit(UiMessage::LayerItemInfo& item);
  void remove(UiMessage::LayerItemInfo& item);
  void remove(qlib::Tag& tag);
  // void edit(Info& info);
};

class Manager {
 public:
  Manager(){};
  ~Manager(){};

  void add(const qlib::Tag& tag) {
    auto& it = layers[tag];
    it.random();
  };
  void add(const qlib::Tag& tag, const Info& info) { layers[tag] = info; };

  void add(UiMessage::LayerItemInfo& item) {
    auto& it = layers[qlib::Tag{item.layer_number, 0}];
    it.load(item);
  };

  void edit(UiMessage::LayerItemInfo& item) {
    auto& it = layers[qlib::Tag{item.layer_number, 0}];
    it.load(item);
  };

  void remove(const UiMessage::LayerItemInfo& item) {
    auto it = layers.find(qlib::Tag{item.layer_number, 0});
    if (it != layers.end()) {
      layers.erase(it);
    }
  }

  void remove(const qlib::Tag& tag) {
    auto it = layers.find(tag);
    if (it != layers.end()) {
      layers.erase(it);
    }
  }

  void clear() { layers.clear(); }

  bool is_hide(const qlib::Tag& tag) {
    if (layers.find(tag) != layers.end()) {
      return layers[tag].layer_hide;
    }
    return false;
  }

  void set_hide(const qlib::Tag& tag, bool layer_hide) {
    if (layers.find(tag) != layers.end()) {
      layers[tag].layer_hide = layer_hide;
    }
  }

  bool get_info(const qlib::Tag& tag, Info& info) {
    if (layers.find(tag) != layers.end()) {
      info = layers[tag];
    }
  }

  void add_or_replace(const qlib::Tag& tag, const Info& info) { layers[tag] = info; }

  bool exist(const qlib::Tag& tag) { return layers.find(tag) != layers.end(); }

  Info getInfo(const qlib::Tag& tag) { return layers[tag]; }
  Info getInfo(uint32_t num) { return layers[qlib::Tag{num, 0}]; }

  std::unordered_map<qlib::Tag, Info, qlib::Tag::Hash> items() { return layers; }

 private:
  std::unordered_map<qlib::Tag, Info, qlib::Tag::Hash> layers;
};

}  // namespace qbe::layer